package com.bwie.service.impl;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.system.UserInfo;
import com.alibaba.fastjson.JSONObject;
import com.bwie.common.constants.Constants;
import com.bwie.common.constants.JwtConstants;
import com.bwie.common.constants.TokenConstants;
import com.bwie.common.domain.User;
import com.bwie.common.domain.request.UserLoginReq;
import com.bwie.common.domain.response.UserLoginResp;
import com.bwie.common.exceptions.LoginExceptions;
import com.bwie.common.result.Result;
import com.bwie.common.utils.ImageVerificationCode;
import com.bwie.common.utils.JwtUtils;
import com.bwie.common.utils.StringUtils;
import com.bwie.remote.RemoteSystemService;
import com.bwie.service.AuthService;
import com.bwie.sms.SendSmsUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @className: AuthServiceImpl
 * @Description: TODO
 * @version: v1.８.0
 * @author: 李明
 * @date: 2025/10/22 9:49
 */
@Service
public class AuthServiceImpl implements AuthService {

    private static final String ERROR_COUNT_KEY = "error_count_key";

    private static final Integer MAX_ERROR_COUNT = 3;
    private static final String SEND_CODE_KEY = "send_code_key";

    @Autowired
    private RemoteSystemService remoteSystemService;

    @Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private SendSmsUtils sendSmsUtils;

    @Autowired
    private HttpServletRequest request;


    /**
     * 生成图片验证码
     *
     * @param outputStream
     */
    @Override
    public void getImageCode(OutputStream outputStream) {
        ImageVerificationCode imageVerificationCode = new ImageVerificationCode();
        BufferedImage image = imageVerificationCode.getImage();
        String text = imageVerificationCode.getText();
        System.out.println("-----------"+text+"-------------");
        try {
            ImageVerificationCode.output(image,outputStream);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 账号登录
     *
     * @param userLoginReq
     */
    @Override
    public UserLoginResp doLogin(UserLoginReq userLoginReq) {
        String username = userLoginReq.getUsername();
        String password = userLoginReq.getPassword();
        //账号校验
        validateData(username,password);
        //判断该用户是否已注册
        Result<User> userInfo = remoteSystemService.getUserInfo(username);
        if (userInfo.getCode()==Constants.ERROR){
            throw new LoginExceptions(Constants.SYSTEM_ERROR_CODE,
                    Constants.SYSTEM_ERROR_MSG);
        }
        User user = userInfo.getData();

        //校验密码 加密
        //1.获取错误次数的键
        String errorCountKey = ERROR_COUNT_KEY + username;

        //2.获取数据库中的密码
        String enPassword = user.getPassword();
        boolean matches = bCryptPasswordEncoder.matches(password, enPassword);
        if (!matches){
            Integer errorCount = (Integer) redisTemplate.opsForValue().get(errorCountKey);
            if (null == errorCount){
                errorCount = 0;
            }
            //错误次数加1
            errorCount++;
            //错误次数大于等于3时
            if (errorCount >= MAX_ERROR_COUNT){
                redisTemplate.opsForValue().set(errorCountKey, errorCount, 5, TimeUnit.MINUTES);
                throw new LoginExceptions(Constants.ERROR_COUNT_OVER_CODE,
                        Constants.ERROR_COUNT_OVER_MSG);
            }
            //错误次数小于3时
            //获取剩余错误次数
            Integer remindCount = MAX_ERROR_COUNT - errorCount;
            redisTemplate.opsForValue().set(errorCountKey,errorCount, 5, TimeUnit.MINUTES);
            String format = String.format(Constants.REMIND_ERROR_COUNT_MSG, remindCount);
            throw new LoginExceptions(Constants.REMIND_ERROR_COUNT_CODE,format);
        }

        //生成token
        HashMap<String, Object> map = new HashMap<>();
        String userKey = IdUtil.simpleUUID();
        map.put(JwtConstants.USER_KEY, userKey);
        String token = JwtUtils.createToken(map);

        //将token存入Redis中
        redisTemplate.opsForValue().set(TokenConstants.LOGIN_TOKEN_KEY + userKey,
                user, 24, TimeUnit.HOURS);

        //创建UserLoginResp对象
        UserLoginResp userLoginResp = new UserLoginResp();
        userLoginResp.setToken(token);
        userLoginResp.setExpireTimeStr(Constants.EXPIRE_TIME);

        //删除错误次数的键值
        redisTemplate.delete(errorCountKey);

        //返回给前台
        return userLoginResp;
    }

    /**
     * 通过手机号发送验证码
     *
     * @param phone
     */
    @Override
    public void sendCode(String phone) {
        //手机号验证
        validateByPhone(phone);
        //通过手机号判断该用户信息是否注册
        Result<User> result = remoteSystemService.getUserByPhone(phone);
        if (result.getCode()==Constants.ERROR){
            throw new LoginExceptions(Constants.SYSTEM_ERROR_CODE,
                    Constants.SYSTEM_ERROR_MSG);
        }
        User user = result.getData();
        if (null == user){
            User userInfo = new User();
            userInfo.setPhone(phone);
            //进行注册
            remoteSystemService.addUserInfo(userInfo);
        }

        //生成验证码
        String code = RandomUtil.randomNumbers(4);
        System.out.println("**********"+code+"*************");

        //将验证码存入Redis中
        redisTemplate.opsForValue().set(SEND_CODE_KEY + phone, code, 10, TimeUnit.MINUTES);

        //发送验证码
//        sendSmsUtils.sendSms(phone, JSONObject.toJSONString(new HashMap<String,Object>(){{
//            put("code",code);
//        }}));
    }

    /**
     * 手机号登录
     *
     * @param userLoginReq
     */
    @Override
    public UserLoginResp doLoginByPhone(UserLoginReq userLoginReq) {
        String phone = userLoginReq.getPhone();
        String code = userLoginReq.getCode();
        //手机号验证
        validateByPhone(phone);
        //通过手机号判断该用户信息是否注册
        Result<User> result = remoteSystemService.getUserByPhone(phone);
        if (result.getCode()==Constants.ERROR){
            throw new LoginExceptions(Constants.SYSTEM_ERROR_CODE,
                    Constants.SYSTEM_ERROR_MSG);
        }
        User user = result.getData();
        if (null == user){
            throw new LoginExceptions(Constants.LOGIN_PERSON_DATA_BLANK_CODE,
                    Constants.LOGIN_PERSON_DATA_BLANK_MSG);
        }

        //校验验证码
        //1.非空
        if (StringUtils.isBlank(code)){
            throw new LoginExceptions(Constants.LOGIN_CODE_BALNK_CODE,
                    Constants.LOGIN_CODE_BLNAK_MSG);
        }
        //2.是否错误
        String enCode = (String) redisTemplate.opsForValue().get(SEND_CODE_KEY + phone);
        if (!StringUtils.equals(code,enCode)){
            throw new LoginExceptions(Constants.LOGIN_CODE_ERROR_CODE,
                    Constants.LOGIN_CODE_ERROR_MSG);
        }

        //校验成功
        //生成token
        Map<String, Object> map = new HashMap<>();
        String userKey = IdUtil.simpleUUID();
        map.put(JwtConstants.USER_KEY, userKey);
        String token = JwtUtils.createToken(map);

        //将token存入Redis中
        redisTemplate.opsForValue().set(TokenConstants.LOGIN_TOKEN_KEY + userKey,
                user, 24, TimeUnit.HOURS);

        //创建UserLoginResp对象
        UserLoginResp userLoginResp = new UserLoginResp();
        userLoginResp.setToken(token);
        userLoginResp.setExpireTimeStr(Constants.EXPIRE_TIME);

        //响应给前台
        return userLoginResp;
    }

    /**
     * 获取登录人信息
     *
     * @return
     */
    @Override
    public User getUserInfo() {
        String token = request.getHeader(TokenConstants.TOKEN);
        String userKey = JwtUtils.getUserKey(token);
        User user = (User) redisTemplate.opsForValue().get(TokenConstants.LOGIN_TOKEN_KEY + userKey);
        return user;
    }


    /**
     * 手脚校验
     * @param phone
     */
    private void validateByPhone(String phone) {
        boolean matches = phone.matches("^1[3-9][0-9]{9}$");
        if (!matches){
            throw new LoginExceptions(Constants.LOGIN_PHONE_ERROR_CODE,
                    Constants.LOGIN_PHONE_ERROR_MSG);
        }
        if (StringUtils.isBlank(phone)){
            throw new LoginExceptions(Constants.LOGIN_PHONE_ERROR_CODE,
                    Constants.LOGIN_PHONE_ERROR_MSG);
        }
    }

    /**
     * 账号校验
     * @param username
     * @param password
     */
    private void validateData(String username, String password) {
        if (StringUtils.isBlank(username)){
            throw new LoginExceptions(Constants.LOGIN_DATA_BLANK_CODE,
                    Constants.LOGIN_DATA_BLANK_MSG);
        }
        if (StringUtils.isBlank(password)){
            throw new LoginExceptions(Constants.LOGIN_DATA_BLANK_CODE,
                    Constants.LOGIN_DATA_BLANK_MSG);
        }
    }

    public static void main(String[] args) {
        BCryptPasswordEncoder cryptPasswordEncoder = new BCryptPasswordEncoder();
        String encode = cryptPasswordEncoder.encode("a123456");
        System.out.println(encode);
    }

}
